import os
from urllib import parse
from .base import BaseTLClient
from finance_c2c.local_settings import TLBaseUrl, TLB2CBaseUrl, ONLINE, BASE_DIR, Config
from core.tools.get_datetime import GetDateTime
from core.tools.func_utils import FuncUtils
from core.tools.encryption import hashlib_md5
from core.tools.models import PublicPrivate


class TLClient(BaseTLClient):
    def __init__(self, TLAppID, TLMchId, private_key=None, pkcs1_rsa_public=None, channel_key=None, sign_type=1):
        super(TLClient, self).__init__(
            TLAppID, TLMchId, TLBaseUrl, private_key=private_key, pkcs1_rsa_public=pkcs1_rsa_public
        )
        self.base_url = TLBaseUrl
        self.channel_key = channel_key
        self.sign_type = sign_type

    # 注册
    def register_get_token(self, mobile, merchant_user_id):
        """
        :param mobile: 手机号
        :param merchant_user_id: 商户会员编号
        :return:
        """
        url = "/h5pay/registerUser.do"
        en_mobile = self.encrypt_with_rsa(mobile)
        params = {
            "version": "1.0", "appId": self.appid, "merchantId": self.mch_id, "signType": "",
            "merchantUserId": merchant_user_id, "accountType": "1", "mobileNo": en_mobile, "registerSource": "H5",
            "requestDatetime": GetDateTime.format_datetime()
        }
        if self.sign_type == 1:
            params["signType"] = 5
        content = self.sign_msg_stored(params)
        sign = self.to_sign_with_private_key(content)
        params["signMsg"] = sign
        response = self.get(url=url, params=params)
        print(response, 'registerUser')
        response_sign = response.pop("signMsg")
        result = parse.urlencode(response)
        md5_result = hashlib_md5(result).upper()
        verify_result = self.to_verify_with_public_key(response_sign, md5_result)
        if verify_result:
            return response
        else:
            raise Exception("返回信息证书验证不通过")

    # 登录
    def login_get_token(self, user_id):
        """
        :param user_id: 通联用户id
        :return:
        """
        url = "/h5pay/takeToken.do"
        key_sorted = ["version", "signType", "appId", "merchantId", "userId", "requestDatetime"]
        params = {
            "version": "1.0",  # 网关接收支付请求接口版本
            "signType": "",  # appId私钥签名
            "appId": self.appid,  # 接入机构
            "merchantId": self.mch_id,  # 商户号
            "userId": user_id,
            "requestDatetime": GetDateTime.format_datetime(),  # 请求时间
        }
        if self.sign_type == 1:
            params["signType"] = 5
        content = self.sign_msg_stored(params, base_sorted=key_sorted)
        sign = self.to_sign_with_private_key(content)
        params["signMsg"] = sign
        params["registNum"] = self.mch_id
        response = self.get(url=url, params=params)
        return response

    # 支付
    def h5pay_api(self, merchant_user_id, mobile, order_amount, order_datetime, order_no=None, pickupUrl=None,
                  receiveUrl=None, ext1=None, ext2=None):
        """
        h5 支付接口
        :param merchant_user_id: 商户用户编号
        :param mobile: 未加密的手机号
        :param order_amount: 订单价格
        :param order_datetime: 订单时间
        :param order_no: 商家订单号
        :param pickupUrl: 用户支付成功后界面跳转的url地址  # 通联文档好像写错了
        :param receiveUrl: 异步通知支付结果url
        :return: redirect_url 跳转的url
        """
        print(pickupUrl, "pickupUrl")
        print(receiveUrl, "receiveUrl")
        if not order_no:
            order_no = FuncUtils().unique_value
        url = "/h5pay/index.do?newVersion=1.0"
        mobile = self.encrypt_with_rsa(mobile)
        key_sorted = ["inputCharset", "pickupUrl", "receiveUrl", "version", "signType", "merchantId",
                      "merchantUserId", "merchantMobileNo", "orderNo", "orderAmount", "orderCurrency",
                      "orderDatetime", "orderExpireDatetime", "productName", "productId", "productDesc",
                      "ext1", "ext2", "extTL", "payType", "businessCode", "merchantBranchCode", "teamCode",
                      "payRule", "subBusinessType", "appId"]
        params = {
            "inputCharset": "1",  # 字符集 1代表UTF-8、2代表GBK、3代表GB2312
            "pickupUrl": pickupUrl,  # 用户支付成功后界面跳转的url地址
            "receiveUrl": receiveUrl,  # 异步通知支付结果url
            "version": "1.0",  # 网关接收支付请求接口版本
            "merchantId": self.mch_id,  # 商户号
            "merchantUserId": merchant_user_id,  # 商户用户编号
            "merchantMobileNo": mobile,  # 加密后的手机号
            "orderNo": order_no,  # 商户（我）生成的订单号
            "orderAmount": order_amount,  # 订单金额
            "orderCurrency": "0",  # 0 代表人民币
            "orderDatetime": order_datetime,  # 订单时间
            "orderExpireDatetime": "120",  # 订单过期时间 过期后需要生成不同的订单
            "appId": self.appid,  # 接入机构
            "ext1": ext1,  # 扩展字段1 供商户使用，英文或中文字符串，支付完成后，按照原样返回给商户
            "ext2": ext2,  # 扩展字段2  供商户使用，英文或中文字符串，支付完成后，按照原样返回给商户
            "subBusinessType": "0612",
            "signType": ""
        }
        if self.sign_type == 1:
            params["signType"] = 5
        content = self.sign_msg_stored(params, base_sorted=key_sorted)
        sign = self.to_sign_with_private_key(content)
        params["signMsg"] = sign
        params = self.delete_none(**params)
        print(params)
        return "%s%s&%s" % (self.base_url, url, parse.urlencode(params))

    # 个人中心
    def h5_my_center_api(self, merchant_user_id, token, user_id):
        """
        h5 会员中心接口
        :param merchant_user_id: 商户用户编号
        :param token: 通联用户牌
        :param user_id: 通联用户编号
        :return: 跳转的url
        """
        url = "/h5pay/myCenter.do"
        key_sorted = ["version", "signType", "appId", "merchantId", "merchantUserId", "token",
                      "userId", "requestDatetime", "pickupUrl"]
        params = {
            "version": "1.0",  # 网关接收支付请求接口版本
            "signType": "",  # appId私钥签名
            "appId": self.appid,  # 接入机构
            "merchantId": self.mch_id,  # 商户号
            "merchantUserId": merchant_user_id,  # 商户用户编号
            "userId": user_id,  # 通联用户编号
            "token": token,  # 通联用户牌
            "requestDatetime": GetDateTime.format_datetime(),  # 请求时间
        }
        if self.sign_type == 1:
            params["signType"] = 5
        content = self.sign_msg_stored(params, base_sorted=key_sorted)
        sign = self.to_sign_with_private_key(content)
        params["signMsg"] = sign
        params["registNum"] = self.mch_id
        return "%s%s?%s" % (self.base_url, url, parse.urlencode(params))

    # 申请退款
    def refund_api(self, refund_amount, order_no, order_datetime, out_refund_no):
        """
        :param refund_amount: 退款金额
        :param order_no: 支付时的订单号
        :param order_datetime: 提交订单时的时间
        :param out_refund_no: 商户退款订单号
        :return:
        """
        if ONLINE:
            url = "https://wanjia.allinpay.com/h5pay/refund.do"
        else:
            url = "/h5pay/refund.do"
        key_sorted = ["version", "signType", "merchantId", "orderNo", "refundAmount", "mchtRefundOrderNo",
                      "orderDatetime", "appId"]
        params = {
            "version": "1.0",  # 网关接收支付请求接口版本
            "signType": "",  # appId私钥签名
            "appId": self.appid,  # 接入机构
            "merchantId": self.mch_id,  # 商户号
            "orderNo": order_no,  # 支付时的订单号
            "refundAmount": refund_amount,  # 退款金额
            "orderDatetime": order_datetime,  # 提交订单时的时间
            "mchtRefundOrderNo": out_refund_no,  # 商户退款订单号
        }
        if self.sign_type == 1:
            params["signType"] = 5
        content = self.sign_msg_stored(params, base_sorted=key_sorted)
        sign = self.to_sign_with_private_key(content)
        params["signMsg"] = sign
        print(params, "tonglian refund_api")
        response = self.get(url=url, params=params)
        print(response, "tl_return")
        return response

    # 退款查询
    def refund_search(self, refund_amount, order_no):
        """
        :param refund_amount: 退款金额
        :param order_no: 支付时的订单号
        :return:
        """
        url = "/h5pay/refundQuery.do"
        key_sorted = ["version", "signType", "merchantId", "orderNo", "refundAmount", "appId"]
        params = {
            "version": "1.0",  # 网关接收支付请求接口版本
            "signType": "",  # appId私钥签名
            "merchantId": self.mch_id,  # 商户号
            "orderNo": order_no,  # 支付时的订单号
            "refundAmount": refund_amount,  # 退款金额
        }
        if self.sign_type == 1:
            params["signType"] = 5
            params["appId"] = self.appid
        content = self.sign_msg_stored(params, base_sorted=key_sorted)
        sign = self.to_sign_with_private_key(content)
        params["signMsg"] = sign
        response = self.get(url=url, params=params)
        print(response, "tl_return_search")
        return response


class TLTransfer(BaseTLClient):
    def __init__(self, TLAppID, TLMchId, private_key=None):
        super(TLTransfer, self).__init__(
            TLAppID, TLMchId, TLB2CBaseUrl, private_key=private_key
        )

    def transfer_b2c(self, user_id, cash, SHDD, server_code="B1006_0004_92"):
        """
        :param user_id:
        :param cash: 转账金额
        :param SHDD: 订单号， 不能重复
        :param server_code: 接口代码
        :return:
        """
        url = "/payment.paymentGateway/dispatchControl/soa"
        # 根据商户会员编码代发
        # ZHLX = "2"
        # YHBH = None
        # SHHYID = ""
        # XM = None
        # SJHM = None
        # SFZH = None

        # 根据身份信息代发
        # ZHLX = "3"
        # YHBH = None
        # SHHYID = None
        # XM = ""
        # SJHM = ""
        # SFZH = ""
        params = {
            "SHBH": self.mch_id,  # 商户号
            "FFLX": "1",  # 发放类型 1现金发放 2积分发放
            "YWZL": "6002",  # 发放类型 6002普通代发 6003代发+冻结
            "FFGZ": "2",  # 发放规则 1：账户未开通直接报错(默认) 2：账户未开通挂账
            "ZHLX": "1",  # 代发账号类型 1.会员编号 2.对方会员编号 3.手机号
            "YHBH": user_id,
            "DFJE": cash,  # 发放金额 单位分
            "BZXX": "",  # 备注信息
            "SHDD": SHDD
        }
        serial_value = FuncUtils().unique_value  # 操作流水号
        timestamp = GetDateTime.format_datetime()
        source = self.appid + timestamp + self.get_source_string(params) + serial_value
        signature = self.to_sign_with_private_key(source)
        head = {
            "sysId": self.appid,
            "charset": "UTF-8",
            "timestamp": timestamp,
            "serialValue": serial_value,
            "version": "3.0",
            "orgcode": self.appid,
        }
        body = {
            "serviceCode": server_code,
            "parameters": params,
        }
        envelope = {
            "head": head,
            "body": body
        }
        post_data = {
            "envelope": envelope,
            "signature": signature
        }
        print(post_data, "post_data")
        response = self.post(url=url, json=post_data)
        return response

    def order_search(self, start_time, end_time, start_sn="1", end_sn="10", server_code="C301310", TLDD=None,
                     SHDD=None, ORDER_STATE=None, ORDER_TYPE=None):
        """
        单笔订单查询
        :param start_time:
        :param end_time:
        :param start_sn:
        :param end_sn:
        :param server_code:
        :param TLDD: 通联商户订单号
        :param SHDD: 商户订单号
        :param ORDER_STATE:
        :param ORDER_TYPE:
        :return:
        """
        url = "/payment.paymentGateway/dispatchControl/soa"
        params = {
            "MERCHANT_ID": self.mch_id,  # 商户号
            "ORDER_STATE": ORDER_STATE,
            "ORDER_TYPE": ORDER_TYPE,  # 订单类型
            "TRADE_TYPE": None,
            "SUBTRADE_TYPE": None,
            "ORDER_ID": TLDD,  # 通联商户订单号
            "ORDER_NO": SHDD,  # 商户订单号
            "START_DATE": start_time,  # 起始查询日期 yyyyMMdd
            "END_DATE": end_time,  # 起始查询日期 yyyyMMdd 最大不超过7天
            "START_SN": start_sn,  # 起始笔数 首次查询送1
            "END_SN": end_sn,  # 起始笔数 首次查询送1
        }
        params = self.parameters_put(params)
        serial_value = FuncUtils().unique_value  # 操作流水号
        timestamp = GetDateTime.format_datetime()
        source = self.appid + timestamp + self.get_source_string(params) + serial_value
        signature = self.to_sign_with_private_key(source)
        head = {
            "sysId": self.appid,
            "charset": "UTF-8",
            "timestamp": timestamp,
            "serialValue": serial_value,
            "version": "3.0",
            "orgcode": self.appid,
        }
        body = {
            "serviceCode": server_code,
            "parameters": params,
        }
        envelope = {
            "head": head,
            "body": body
        }
        post_data = {
            "envelope": envelope,
            "signature": signature
        }
        print(post_data, "post_data")
        response = self.post(url=url, json=post_data)
        return response


class TlAuth(BaseTLClient):
    def __init__(self):
        """
        :param private_key:  通联公钥
        :param pkcs1_rsa_public:
        """

        private_key = os.path.join(BASE_DIR, "core/tl/yp_private").replace("\\", "/")  # 我方私钥
        # if ONLINE:
            # private_key = os.path.join(BASE_DIR, "core/tl/tl_Oauth_private.pem").replace("\\", "/")  # 我方私钥
            # pkcs1_rsa_public = os.path.join(BASE_DIR, "core/tl/tlOauthPublic").replace("\\", "/")  # 通联公钥
        # else:
            # private_key = os.path.join(BASE_DIR, "core/tl/yp_private").replace("\\", "/")  # 我方私钥
            # pkcs1_rsa_public = os.path.join(BASE_DIR, "core/tl/tlOauthPublicTest").replace("\\", "/")  # 通联公钥
        super(TlAuth, self).__init__(None, None, None, private_key=private_key, pkcs1_rsa_public=None)


def get_TLClient(channel_key=None):
    if not channel_key:
        channel_key = "youpinhuiyuan"
    print("channel_key:", channel_key)
    pp_key_h5 = PublicPrivate.objects.get(company="tonglianqianbao", file_type=1, func_type="H5",
                                          channel_key=channel_key)
    h5_client = TLClient(pp_key_h5.app_id, pp_key_h5.TLMchId, pp_key_h5.private_file.path,
                         pkcs1_rsa_public=pp_key_h5.public_file.path, channel_key=channel_key,
                         sign_type=pp_key_h5.sign_type)
    return h5_client


def get_TLTransfer(channel_key=None):
    if not channel_key:
        channel_key = "youpinhuiyuan"
    info = PublicPrivate.objects.get(company="tonglianqianbao", file_type=2, func_type="B2CTransfer",
                                     hannel_key=channel_key)
    return TLTransfer(info.app_id, info.TLMchId, private_key=info.private_file)
